package com.trg.flex.dt
{
	import com.trg.flex.FlexUtils;
	import com.trg.flex.dp.NestedSort;
	
	import mx.collections.Sort;
	import mx.collections.SortField;
	import mx.controls.dataGridClasses.DataGridColumn;
	import mx.core.IFactory;
	import mx.formatters.Formatter;
	
	[Exclude(name="dataField", kind="property")]
	
	/**
	 * Fired when a cell in this column is clicked.
	 */
	[Event(name="clickAction",type="com.trg.flex.dt.DataTableEvent")]
	/**
	 * Fired when a cell in this column is double-clicked.
	 */
	[Event(name="doubleClickAction",type="com.trg.flex.dt.DataTableEvent")]
	/**
	 * Columns are used with DataTable and extend the basic DataGridColumn with
	 * several additional options. They play a part in making nested properties possible.
	 * They also provide the option to display a text, a link, a button or an icon in
	 * the column simply by setting a property, and they provide a defaultSort option.
	 * Responding to user action is also made easier with clickAction and doubleClickAction events.
	 */
	public class Column extends DataGridColumn implements IFactory
	{
		public function Column(field:String=null, headerText:String=null)
		{
			super();
			this.field = field;
			this.headerText = headerText;
		}
		
		/**
		 * <b>***NOT IMPLEMENTED***</b> If specified, This icon will be displayed in each cell instead of text.
		 */
		public var icon:Class;
		/**
		 * If specified, this string will be used as the display value for each
		 * cell in this column instead of using the field to determine a display value.
		 */
		public var label:String;
		/**
		 * Formatter to use to convert the value displayed in this column to a string.
		 */
		public var formatter:Formatter;
		/**
		 * Text to display if the value of a cell is <code>null</code>.
		 */
		public var noValueLabel:String;
		
		protected var _field:String;
		protected var chain:Array;
		protected var _dataTable:DataTable;
		protected var _showAs:String;
		
		/**
		 * If default sort is “asc” or “desc” and field is specified, the DataTable
		 * will be sorted by the given field in the order specified by this property.
		 * This property should only be set on one Column per DataTable.If default
		 * sort is “asc” or “desc” and field is specified, the DataTable will be sorted
		 * by the given field in the order specified by this property. This property 
		 * should only be set on one Column per DataTable.
		 */
		[Inspectable(enumeration="asc,desc")]
		[Bindable]
		public var defaultSort:String;
		
		/**
		 * The DataTable with which this column is associated. This is set automatically
		 * and should not be set manually.
		 */
		[Bindable]
		public function get dataTable():DataTable {
			return _dataTable;
		}
		public function set dataTable(value:DataTable):void {
			if (_dataTable != null) {
				_dataTable.removeEventListener(DataTableEvent.CLICK, actionHandler);
				_dataTable.removeEventListener(DataTableEvent.DOUBLE_CLICK, actionHandler);
			}
			_dataTable = value;
			if (_dataTable != null) {
				_dataTable.addEventListener(DataTableEvent.CLICK, actionHandler);
				_dataTable.addEventListener(DataTableEvent.DOUBLE_CLICK, actionHandler);
				if (defaultSort != null && defaultSort != "") {
					var s:Sort = new NestedSort();
					s.fields = [new SortField(_field, false, defaultSort == "desc")];
					_dataTable.sort = s;
				}
			}
		}
		
		public function actionHandler(event:DataTableEvent):void {
			if (event.column == this) {
				dispatchEvent(event.copy());
			}
		} 
		
		/**
		 * This value is used to determine the display value and also the sort value for
		 * the column. It can take nested properties. (see Terms:Nested Properties.)
		 */
		[Bindable]
		public function get field():String {
			return _field;
		}
		public function set field(value:String):void {
			if (value != null && value.indexOf(".") != -1) {
				chain = value.split(".");
			} else {
				chain = null;
			}
			_field = value;
			dataField = value;
		}
		
		/**
		 * Determines whether the cells are rendered as plain text, a button or a link.
		 * In each case the text is displayed.
		 */
		[Inspectable(enumeration="text,button,link,icon", defaultValue="text")]
		public function set showAs(value:String):void {
			_showAs = value;
			if (value == "text") {
				this.itemRenderer = null;
			} else {
				this.itemRenderer = this;
			}
		}
		public function get showAs():String {
			return _showAs;
		}
		
		public function newInstance():* {
			if (_showAs == "button") {
				return new ButtonRenderer(this);
			} else if (_showAs == "link") {
				return new LinkButtonRenderer(this);
			}
		}
		
		
		override public function itemToLabel(data:Object):String
	    {
	        if (label != null) {
	        	return label;
	        }
	        
	        if (labelFunction != null) {
	        	try { //try two arguments
					return labelFunction(data, this);
				} catch (err:Error) {
					if (err.name == "ArgumentError" && err.message.substr(0, 12) == "Error #1063:")
						return labelFunction(data); //try one argument
					else
						throw err;
				}
	        }
	        
	        if (!data)
	            return noValueLabel ? noValueLabel : " ";
	        
	        if ((formatter == null && chain == null) || (typeof(data) != "object" && typeof(data) != "xml"))
	        	return super.itemToLabel(data);
	        	
	        if (data.hasOwnProperty(_field)) {
	        	data = data[_field];
	        } else {
	       		data = FlexUtils.getChainedProperty(data, chain);
	       	}
	        if (data == null) return noValueLabel ? noValueLabel : " ";;
	        
	        if (formatter != null) {
	        	return formatter.format(data);
	        }
	        
	        if (data is String)
	            return String(data);
	
	        try {
	            return data.toString();
	        } catch(e:Error) {
	        }
	
	        return noValueLabel ? noValueLabel : " ";;
	    }
	}
}